package be.rivendale.mathematics;

import static be.rivendale.mathematics.MathematicalAssert.*;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;

public class PointTest {
    @Test
    public void constructorByCoordinatesSetsCoordinates() throws Exception {
        Point point = new Triple(1, 2, 3);
        assertRealEquals(1, point.getX());
        assertRealEquals(2, point.getY());
        assertRealEquals(3, point.getZ());
    }

    @Test(expected = IllegalArgumentException.class)
    public void addThrowsIllegalArgumentExceptionWhenPointParameterIsNull() throws Exception {
        new Triple(1, 2, 3).add((Point) null);
    }

    @Test
    public void subtractThrowsIllegalArgumentExceptionWhenPointParameterIsNull() throws Exception {
        try {
            new Triple(1, 2, 3).subtract(null);
        } catch(IllegalArgumentException expectedException) {
            assertEquals("point may not be null when subtracting points.", expectedException.getMessage());
        }
    }

    @Test
    public void subtractDoesNotChangeStateOfThisPoint() throws Exception {
        Point point = new Triple(1, 2, 3);
        point.subtract(new Triple(4, 5, 6));
        assertPointEquals(new Triple(1, 2, 3), point);
    }

    @Test
    public void addDoesNotChangeStateOfThisPoint() throws Exception {
        Point point = new Triple(1, 2, 3);
        point.add(new Triple(4, 5, 6));
        assertPointEquals(new Triple(1, 2, 3), point);
    }

    @Test
    public void subtractDoesNotChangeStateOfTheParameterPoint() throws Exception {
        Point point = new Triple(1, 2, 3);
        new Triple(4, 5, 6).subtract(point);
        assertPointEquals(new Triple(1, 2, 3), point);
    }

    @Test
    public void addDoesNotChangeStateOfTheParameterPoint() throws Exception {
        Point point = new Triple(1, 2, 3);
        new Triple(4, 5, 6).add(point);
        assertPointEquals(new Triple(1, 2, 3), point);
    }

    @Test
    public void subtractRetunsDifferenceOfTheTwoInvolvedPoints() throws Exception {
        Point point = new Triple(1, 2, 3).subtract(new Triple(4, 5, 6));
        assertPointEquals(new Triple(-3, -3, -3), point);
    }

    @Test
    public void addReturnsDifferenceOfTheTwoInvolvedPoints() throws Exception {
        Point point = new Triple(1, 2, 3).add((Point) new Triple(4, 5, 6));
        assertPointEquals(new Triple(5, 7, 9), point);
    }

    @Test
    public void divideByScalarLeavesStateOfThisObjectUnchanged() throws Exception {
        Point point = new Triple(10, 20, 30);
        point.divide(5);
        assertPointEquals(new Triple(10, 20, 30), point);
    }

    @Test
    public void divideByScalarReturnsNewPointWithEachCoordinateDividedByTheScalarValueSpecified() throws Exception {
        Point point = new Triple(8, 6, 12).divide(2);
        assertPointEquals(new Triple(4, 3, 6), point);
    }

    @Test
    public void equalsReturnsTrueIfTheTwoVectorsAreEqual() throws Exception {
        Point a = new Triple(1, 2, 3);
        Point b = new Triple(1, 2, 3);
        assertTrue(a.equals(b));
    }

    @Test
    public void equalsReturnsFalseOfTheTwoVectorsAreNotEqual() throws Exception {
        Point a = new Triple(1, 2, 3);
        Point b = new Triple(4, 5, 6);
        assertFalse(a.equals(b));
    }

    @Test
    public void toStringReturnsPointInCoordinateRepresentationWithSixDecimalDigits() throws Exception {
        assertEquals("(1.157878, 6.478774, 7.478412)", new Triple(1.1578781, 6.4787742, 7.4784123).toString());
    }

    @Test
    public void asVectorReturnsThisPointAsAVector() {
        Point point = new Triple(1, 2, 3);
        assertVectorEquals(new Triple(1, 2, 3), point.asVector());
    }
}